/*
    Copyright (C) 2021 Huawei Device Co., Ltd.
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.
 */
package com.danikula.videocache.slicingStrategy;

import com.danikula.videocache.*;
import com.danikula.videocache.bean.ProgressBean;
import com.danikula.videocache.interfacers.CacheListener;

import ohos.agp.utils.TextTool;
import ohos.app.Context;
import ohos.data.DatabaseHelper;
import ohos.data.preferences.Preferences;

import java.util.ArrayList;
import java.util.List;

/**
 * 分片缓存策略
 */
public class SlicingCacheStrategy extends CacheStrategy {
    /**
     * 默认文件间距
     */
    private static final long MAX_FILE_OFFSET_CACHE_SIZE = 10 * 1024 * 1024;

    /**
     * 单个碎片文件的最小容量
     */
    private static final long MIN_SINGLE_FILE_SIZE = 5 * 1024 * 1024;

    /**
     * 优化措施
     * 尽量避免生成过多的碎片文件
     * 如果拖动距离离上个碎片很近 那就继续缓存到它里面 不再生成新的文件
     * 此值不建议设太大 否则拖动点离上一个碎片较远 需要等数据请求下来再播放 会造成较大的时延
     */
    private long minFileCacheSize = MAX_FILE_OFFSET_CACHE_SIZE;

    /**
     * 优化措施
     * 由于拖动较快  缓存的数据很少 碎片文件很小
     * 导致一次读取的数据不足 播放卡住 这种文件需要删除
     */
    private long minSingleFileSize = MIN_SINGLE_FILE_SIZE;
    private long fileLength;
    private Preferences pre;

    public long getMinFileCacheSize() {
        return minFileCacheSize;
    }

    public void setMinFileCacheSize(long minFileCacheSize) {
        this.minFileCacheSize = minFileCacheSize;
    }

    public long getMinSingleFileSize() {
        return minSingleFileSize;
    }

    public void setMinSingleFileSize(long minSingleFileSize) {
        this.minSingleFileSize = minSingleFileSize;
    }

    public long getFileLength() {
        return fileLength;
    }


    /**
     * 存储视频文件总长度
     *
     * @param fileLength 视频文件总长度
     */
    public void restoreFileLength(long fileLength) {
        this.fileLength = fileLength;
        if (pre != null) {
            long aLong = pre.getLong(Constants.CACHE_FILE_LENGTH, 0);
            if (aLong == 0) {
                pre.putLong(Constants.CACHE_FILE_LENGTH, fileLength).flush();
            }
        }
    }

    /**
     * 存储当前碎片视频文件路径
     *
     * @param rootPath 碎片视频文件路径
     */
    public void restoreFilePath(String rootPath) {
        if (pre != null && !TextTool.isNullOrEmpty(rootPath)) {
            String path = pre.getString(Constants.CACHE_FILE_PATH, "");
            if (TextTool.isNullOrEmpty(path)) {
                pre.putString(Constants.CACHE_FILE_PATH, rootPath).flush();
            }
        }
    }

    /**
     * 存储完整视频文件路径
     *
     * @param completePath 完整视频文件路径
     */
    public void restoreCompleteFilePath(String completePath) {
        if (pre != null && !TextTool.isNullOrEmpty(completePath)) {
            String path = pre.getString(Constants.CACHE_COMPLETE_FILE_PATH, "");
            if (TextTool.isNullOrEmpty(path)) {
                pre.putString(Constants.CACHE_COMPLETE_FILE_PATH, completePath).flush();
            }
        }
    }

    /**
     * 每次打开APP获取分片存储的数据区域
     * 并转为对应的分段显示进度条的进度值
     * 用于初始化显示当前视频已经缓存的区域
     *
     * @param context       上下文
     * @param cacheVideoUrl 处理过的视频url
     * @return 分段显示进度条的进度值
     */
    public List<ProgressBean> getInitSpData(Context context, String cacheVideoUrl) {
        // 先初始化自定义分段显示进度条0-100的数值
        List<ProgressBean> initData = new ArrayList<>();
        for (int i = 0; i <= 100; i++) {
            ProgressBean bean = new ProgressBean();
            bean.setDefault(true);
            bean.setProgress(i);
            initData.add(bean);
        }
        DatabaseHelper preferences = new DatabaseHelper(context);
        pre = preferences.getPreferences(cacheVideoUrl);
        String rootPath = pre.getString(Constants.CACHE_FILE_PATH, "");
        String completePath = pre.getString(Constants.CACHE_COMPLETE_FILE_PATH, "");
        fileLength = pre.getLong(Constants.CACHE_FILE_LENGTH, 0);
        if (TextTool.isNullOrEmpty(rootPath) || fileLength == 0) {
            return initData;
        }
        // 说明已经文件缓存合并完毕了
        if (!TextTool.isNullOrEmpty(completePath)) {
            for (int i = 0; i < initData.size(); i++) {
                ProgressBean bean = initData.get(i);
                bean.setDefault(false);
                initData.set(i, bean);
            }
            return initData;
        }
        // 获取所有的碎片文件的起始与终点值
        List<long[]> caches = SlicingFileUtil.getFileStartList(cacheVideoUrl, rootPath);
        if (caches == null) {
            return initData;
        }
        transDownloadAreaToProgress(fileLength, caches, initData);
        return initData;
    }

    @Override
    protected ProxyCache createHttpProxyCache(HttpUrlSource source, Config config, CacheListener uiCacheListener,
    String url) throws ProxyCacheException {
        // 防止文件间距数值小于0 或者数据过大导致缓存时间太长 时延久  强制转为默认值
        if (minFileCacheSize < 0 || minFileCacheSize > MAX_FILE_OFFSET_CACHE_SIZE) {
            minFileCacheSize = MAX_FILE_OFFSET_CACHE_SIZE;
        }
        // 单个碎片文件的大小设置的过小 导致读取卡顿 强制转为默认值
        if (minSingleFileSize < MIN_SINGLE_FILE_SIZE) {
            minFileCacheSize = MIN_SINGLE_FILE_SIZE;
        }
        SlicingFileCache cache = new SlicingFileCache(generateCacheFile(config, url), config.diskUsage, this);
        cache.setCacheVideoUrl(config.generateCacheName(url));
        HttpSliceProxyCache sliceProxyCache = new HttpSliceProxyCache(source, cache);
        sliceProxyCache.registerCacheListener(uiCacheListener);
        return sliceProxyCache;
    }
}
